/*
 *
 * Copyright(c) 2010 Safelayer Secure Communications
 *
 * This is open source software, placed under the terms of the
 * GNU GENERAL PUBLIC LICENSE Version 3.
 * Please see: http://www.gnu.org/licenses/gpl-3.0.txt
 * 
 * Permission to use, copy, modify, and distribute this software
 * for any purpose and without fee is hereby granted, provided
 * that the above copyright notices appear in all copies and that
 * both the copyright notice and this permission notice appear in
 * supporting documentation.
 * 
 */
package com.neuralnoise.foaf.core;

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.Resource;

/**
 *  Name match based smushing FOAF rule.
 * 
 * @author victor.martinez <swtp@safelayer.com>
 * 
 */
public class NameMatchRule extends Rule {

	public static final int MIN_TOKENS_EXPECTED = 2;

	private Property nameProperty;

	private Property firstNameProperty;

	private Property givenNameProperty;

	private Property familyNameProperty;

	public NameMatchRule() {
		super("Name Match");
		nameProperty = FOAFVocabulary.name;
		firstNameProperty = FOAFVocabulary.firstName;
		givenNameProperty = FOAFVocabulary.givenName;
		familyNameProperty = FOAFVocabulary.familyName;
	}

	@Override
	public boolean equals(Resource resource1, Resource resource2) {
		if (!resource1.hasProperty(nameProperty) && !resource2.hasProperty(nameProperty))
			return false;

		if (resource1.hasProperty(nameProperty))
			return equalsUsingNameMatching(resource1, resource2);
		
		if (resource2.hasProperty(nameProperty))
			return equalsUsingNameMatching(resource2, resource2); // reverse
		
		return false;
	}

	@Override
	public boolean isTrustEquals() {
		return false;
	}

	// Helpers -----------------------------------------------------------------------------------
	
	private boolean equalsUsingNameMatching(Resource resource1, Resource resource2) {
		// tokenize the name
		String name1 = resource1.getProperty(nameProperty).getLiteral().toString();
		List<String> names = tokenizeComposedName(name1);
		if (names.size() < MIN_TOKENS_EXPECTED) // 2 tokens minimum
			return false;
		
		String firstName = resource2.hasProperty(firstNameProperty) ?
				getLiteralFromProperty(resource2,firstNameProperty) : null;
		String givenName = resource2.hasProperty(givenNameProperty) ?
				getLiteralFromProperty(resource2,givenNameProperty) : null;
		String familyName = resource2.hasProperty(familyNameProperty) ?
				getLiteralFromProperty(resource2,familyNameProperty) : null;
			
		if (names.contains(firstName) && names.contains(familyName))
			return true;
		else if (names.contains(givenName) && names.contains(familyName))
			return true;
		else
			return false;
	}

	private String getLiteralFromProperty(Resource resource, Property property) {
		return resource.getProperty(property).getLiteral().toString();
	}

	private List<String> tokenizeComposedName(String name) {
		StringTokenizer tokens = new StringTokenizer(name);
		List<String> names = new ArrayList<String>();
		while (tokens.hasMoreTokens()) {
			names.add(tokens.nextToken());
		}
		return names;
	}
}
